package com.arnojin.oschina.api.util;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * CharUtil
 *
 * @author arno
 * @date 2021/01/26 21:19
 */
public class CharUtil {
    public static final char[] HEX_CHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    public CharUtil() {
    }

    public static char toChar(byte b) {
        return (char) (b & 255);
    }

    public static byte[] toSimpleByteArray(char[] carr) {
        byte[] barr = new byte[carr.length];

        for (int i = 0; i < carr.length; ++i) {
            barr[i] = (byte) carr[i];
        }

        return barr;
    }

    public static byte[] toSimpleByteArray(CharSequence charSequence) {
        byte[] barr = new byte[charSequence.length()];

        for (int i = 0; i < barr.length; ++i) {
            barr[i] = (byte) charSequence.charAt(i);
        }

        return barr;
    }

    public static char[] toSimpleCharArray(byte[] barr) {
        char[] carr = new char[barr.length];

        for (int i = 0; i < barr.length; ++i) {
            carr[i] = (char) (barr[i] & 255);
        }

        return carr;
    }

    public static int toAscii(char c) {
        return c <= 255 ? c : 63;
    }

    public static byte[] toAsciiByteArray(char[] carr) {
        byte[] barr = new byte[carr.length];

        for (int i = 0; i < carr.length; ++i) {
            barr[i] = (byte) (carr[i] <= 255 ? carr[i] : 63);
        }

        return barr;
    }

    public static byte[] toAsciiByteArray(CharSequence charSequence) {
        byte[] barr = new byte[charSequence.length()];

        for (int i = 0; i < barr.length; ++i) {
            char c = charSequence.charAt(i);
            barr[i] = (byte) (c <= 255 ? c : 63);
        }

        return barr;
    }

    public static byte[] toRawByteArray(char[] carr) {
        byte[] barr = new byte[carr.length << 1];
        int i = 0;

        for (int var3 = 0; i < carr.length; ++i) {
            char c = carr[i];
            barr[var3++] = (byte) ((c & '\uff00') >> 8);
            barr[var3++] = (byte) (c & 255);
        }

        return barr;
    }

    public static char[] toRawCharArray(byte[] barr) {
        int carrLen = barr.length >> 1;
        if (carrLen << 1 < barr.length) {
            ++carrLen;
        }

        char[] carr = new char[carrLen];
        int i = 0;

        char c;
        for (int var4 = 0; i < barr.length; carr[var4++] = c) {
            c = (char) (barr[i] << 8);
            ++i;
            if (i != barr.length) {
                c = (char) (c + (barr[i] & 255));
                ++i;
            }
        }

        return carr;
    }

    public static byte[] toByteArray(char[] carr) {
        return (new String(carr)).getBytes(StandardCharsets.UTF_8);
    }

    public static byte[] toByteArray(char[] carr, Charset charset) {
        return (new String(carr)).getBytes(charset);
    }

    public static char[] toCharArray(byte[] barr) {
        return (new String(barr)).toCharArray();
    }

    public static char[] toCharArray(byte[] barr, Charset charset) {
        return (new String(barr, charset)).toCharArray();
    }

    public static boolean equalsOne(char c, char[] match) {
        char[] var2 = match;
        int var3 = match.length;

        for (int var4 = 0; var4 < var3; ++var4) {
            char aMatch = var2[var4];
            if (c == aMatch) {
                return true;
            }
        }

        return false;
    }

    public static int findFirstEqual(char[] source, int index, char[] match) {
        for (int i = index; i < source.length; ++i) {
            if (equalsOne(source[i], match)) {
                return i;
            }
        }

        return -1;
    }

    public static int findFirstEqual(char[] source, int index, char match) {
        for (int i = index; i < source.length; ++i) {
            if (source[i] == match) {
                return i;
            }
        }

        return -1;
    }

    public static int findFirstDiff(char[] source, int index, char[] match) {
        for (int i = index; i < source.length; ++i) {
            if (!equalsOne(source[i], match)) {
                return i;
            }
        }

        return -1;
    }

    public static int findFirstDiff(char[] source, int index, char match) {
        for (int i = index; i < source.length; ++i) {
            if (source[i] != match) {
                return i;
            }
        }

        return -1;
    }

    public static boolean isWhitespace(char c) {
        return c <= ' ';
    }

    public static boolean isLowercaseAlpha(char c) {
        return c >= 'a' && c <= 'z';
    }

    public static boolean isUppercaseAlpha(char c) {
        return c >= 'A' && c <= 'Z';
    }

    public static boolean isAlphaOrDigit(char c) {
        return isDigit(c) || isAlpha(c);
    }

    public static boolean isWordChar(char c) {
        return isDigit(c) || isAlpha(c) || c == '_';
    }

    public static boolean isPropertyNameChar(char c) {
        return isDigit(c) || isAlpha(c) || c == '_' || c == '.' || c == '[' || c == ']';
    }

    public static boolean isAlpha(char c) {
        return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
    }

    public static boolean isDigit(char c) {
        return c >= '0' && c <= '9';
    }

    public static boolean isHexDigit(char c) {
        return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F';
    }

    public static boolean isGenericDelimiter(int c) {
        switch (c) {
            case 35:
            case 47:
            case 58:
            case 63:
            case 64:
            case 91:
            case 93:
                return true;
            default:
                return false;
        }
    }

    public static boolean isSubDelimiter(int c) {
        switch (c) {
            case 33:
            case 36:
            case 38:
            case 39:
            case 40:
            case 41:
            case 42:
            case 43:
            case 44:
            case 59:
            case 61:
                return true;
            case 34:
            case 35:
            case 37:
            case 45:
            case 46:
            case 47:
            case 48:
            case 49:
            case 50:
            case 51:
            case 52:
            case 53:
            case 54:
            case 55:
            case 56:
            case 57:
            case 58:
            case 60:
            default:
                return false;
        }
    }

    public static boolean isReserved(char c) {
        return isGenericDelimiter(c) || isSubDelimiter(c);
    }

    public static boolean isUnreserved(char c) {
        return isAlpha(c) || isDigit(c) || c == '-' || c == '.' || c == '_' || c == '~';
    }

    public static boolean isPchar(char c) {
        return isUnreserved(c) || isSubDelimiter(c) || c == ':' || c == '@';
    }

    public static char toUpperAscii(char c) {
        if (isLowercaseAlpha(c)) {
            c = (char) (c - 32);
        }

        return c;
    }

    public static char toLowerAscii(char c) {
        if (isUppercaseAlpha(c)) {
            c = (char) (c + 32);
        }

        return c;
    }

    public static int hex2int(char c) {
        switch (c) {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                return c - 48;
            case ':':
            case ';':
            case '<':
            case '=':
            case '>':
            case '?':
            case '@':
            case 'G':
            case 'H':
            case 'I':
            case 'J':
            case 'K':
            case 'L':
            case 'M':
            case 'N':
            case 'O':
            case 'P':
            case 'Q':
            case 'R':
            case 'S':
            case 'T':
            case 'U':
            case 'V':
            case 'W':
            case 'X':
            case 'Y':
            case 'Z':
            case '[':
            case '\\':
            case ']':
            case '^':
            case '_':
            case '`':
            default:
                throw new IllegalArgumentException("Not a hex: " + c);
            case 'A':
            case 'B':
            case 'C':
            case 'D':
            case 'E':
            case 'F':
                return c - 55;
            case 'a':
            case 'b':
            case 'c':
            case 'd':
            case 'e':
            case 'f':
                return c - 87;
        }
    }

    public static char int2hex(int i) {
        return HEX_CHARS[i];
    }
}
